#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
汽车制造公司涂装-总装缓存区调序调度优化问题 - Problem 1
PBS优化调度模型实现
"""

import pandas as pd
import numpy as np
from itertools import combinations
import openpyxl
from datetime import datetime
import warnings
warnings.filterwarnings('ignore')

class PBSOptimizer:
    def __init__(self):
        self.data = None
        self.schedule_matrix = None
        self.objective_scores = {}
        
    def load_data(self):
        """加载输入数据"""
        # 读取附件1数据
        self.data = pd.read_excel('附件1.xlsx')
        self.data.columns = ['sequence', 'config', 'color', 'drive']
        
        # 设置颜色映射
        self.color_map = {
            '燃动': 'combustion',
            '电动': 'electric'
        }
        
        self.drive_map = {
            '两驱': 'two',
            '四驱': 'four'
        }
        
        self.data['color_code'] = self.data['color'].map(self.color_map)
        self.data['drive_code'] = self.data['drive'].map(self.drive_map)
        
        print(f"加载数据完成，共{len(self.data)}条记录")
        return self.data
    
    def calculate_color_changes(self, sequence):
        """计算颜色切换次数"""
        changes = 0
        for i in range(1, len(sequence)):
            if sequence[i] != sequence[i-1]:
                changes += 1
        return changes
    
    def calculate_drive_ratio(self, sequence, window_size=4):
        """计算驱动形式比例偏差"""
        total_deviation = 0
        
        for i in range(0, len(sequence), window_size):
            window = sequence[i:i+window_size]
            if len(window) < 2:
                continue
                
            two_count = window.count('two')
            four_count = window.count('four')
            
            # 计算1:1比例的偏差
            ideal_two = len(window) / 2
            ideal_four = len(window) / 2
            
            deviation = abs(two_count - ideal_two) + abs(four_count - ideal_four)
            total_deviation += deviation
            
        return total_deviation
    
    def calculate_pbs_utilization(self, schedule_matrix):
        """计算PBS缓存区利用率"""
        # 简化的利用率计算
        used_positions = np.sum(schedule_matrix > 0)
        total_positions = schedule_matrix.shape[0] * schedule_matrix.shape[1]
        utilization = used_positions / total_positions
        
        # 返回缺陷值（100 - 利用率*100）
        return 100 - (utilization * 100)
    
    def calculate_total_time(self, schedule_matrix):
        """计算总调度时间"""
        # 简化的总时间计算
        max_time = 0
        for col in range(schedule_matrix.shape[1]):
            col_time = 0
            for row in range(schedule_matrix.shape[0]):
                if schedule_matrix[row, col] > 0:
                    col_time += 9  # 每辆车移动时间9单位
            max_time = max(max_time, col_time)
        
        # 基于题目公式的近似计算
        C = len(np.unique(schedule_matrix[schedule_matrix > 0]))
        T = max_time
        expected_time = 9 * C + 72
        
        time_penalty = max(0, T - expected_time) * 0.01
        return 100 - time_penalty
    
    def generate_initial_schedule(self):
        """生成初始调度方案"""
        n_cars = len(self.data)
        
        # 创建10xN的调度矩阵
        max_cols = max(100, n_cars // 6 + 10)
        schedule = np.zeros((10, max_cols), dtype=int)
        
        # 按原始顺序填充
        car_index = 0
        for col in range(max_cols):
            for row in range(10):
                if car_index < n_cars:
                    schedule[row, col] = self.data.iloc[car_index]['sequence']
                    car_index += 1
                else:
                    break
            if car_index >= n_cars:
                break
                
        return schedule
    
    def improve_schedule(self, schedule):
        """改进调度方案"""
        improved_schedule = schedule.copy()
        n_cars = len(self.data)
        
        # 获取车辆信息
        car_info = {}
        for _, row in self.data.iterrows():
            car_info[row['sequence']] = {
                'color': row['color_code'],
                'drive': row['drive_code']
            }
        
        # 简单的启发式改进
        # 1. 按颜色分组，减少切换
        # 2. 平衡驱动形式比例
        
        # 提取所有车辆
        all_cars = []
        for row in range(schedule.shape[0]):
            for col in range(schedule.shape[1]):
                if schedule[row, col] > 0:
                    all_cars.append(schedule[row, col])
        
        # 按颜色排序
        color_groups = {}
        for car in all_cars:
            color = car_info[car]['color']
            if color not in color_groups:
                color_groups[color] = []
            color_groups[color].append(car)
        
        # 重新排列
        new_order = []
        for color in color_groups:
            new_order.extend(color_groups[color])
        
        # 填充新的调度矩阵
        new_schedule = np.zeros_like(schedule)
        car_index = 0
        for col in range(new_schedule.shape[1]):
            for row in range(10):
                if car_index < len(new_order):
                    new_schedule[row, col] = new_order[car_index]
                    car_index += 1
                else:
                    break
            if car_index >= len(new_order):
                break
                
        return new_schedule
    
    def calculate_objectives(self, schedule):
        """计算四个优化目标得分"""
        # 获取序列信息
        sequence = []
        car_info = {}
        for _, row in self.data.iterrows():
            car_info[row['sequence']] = {
                'color': row['color_code'],
                'drive': row['drive_code']
            }
        
        # 提取调度序列
        for col in range(schedule.shape[1]):
            for row in range(schedule.shape[0]):
                if schedule[row, col] > 0:
                    sequence.append(schedule[row, col])
        
        # 获取颜色和驱动信息
        color_sequence = [car_info[car]['color'] for car in sequence]
        drive_sequence = [car_info[car]['drive'] for car in sequence]
        
        # 计算各目标得分
        # 目标1: 颜色切换次数
        color_changes = self.calculate_color_changes(color_sequence)
        obj1_score = max(0, 100 - color_changes * 2)
        
        # 目标2: 驱动形式比例
        drive_deviation = self.calculate_drive_ratio(drive_sequence)
        obj2_score = max(0, 100 - drive_deviation * 5)
        
        # 目标3: PBS缓存区利用率
        obj3_score = self.calculate_pbs_utilization(schedule)
        
        # 目标4: 总调度时间
        obj4_score = self.calculate_total_time(schedule)
        
        return {
            'color_switching': obj1_score,
            'drive_ratio': obj2_score,
            'pbs_utilization': obj3_score,
            'total_time': obj4_score
        }
    
    def calculate_weighted_score(self, objectives):
        """计算加权总分"""
        weights = {
            'color_switching': 0.4,
            'drive_ratio': 0.3,
            'pbs_utilization': 0.2,
            'total_time': 0.1
        }
        
        weighted_score = 0
        for key in objectives:
            weighted_score += objectives[key] * weights[key]
            
        return weighted_score
    
    def solve(self):
        """求解问题1"""
        print("开始求解Problem 1...")
        
        # 加载数据
        data = self.load_data()
        
        # 生成初始方案
        initial_schedule = self.generate_initial_schedule()
        
        # 改进方案
        improved_schedule = self.improve_schedule(initial_schedule)
        
        # 计算目标得分
        initial_objectives = self.calculate_objectives(initial_schedule)
        improved_objectives = self.calculate_objectives(improved_schedule)
        
        # 计算加权总分
        initial_score = self.calculate_weighted_score(initial_objectives)
        improved_score = self.calculate_weighted_score(improved_objectives)
        
        print("初始方案:")
        for key, value in initial_objectives.items():
            print(f"  {key}: {value:.2f}")
        print(f"初始总分: {initial_score:.2f}")
        
        print("\n改进方案:")
        for key, value in improved_objectives.items():
            print(f"  {key}: {value:.2f}")
        print(f"改进总分: {improved_score:.2f}")
        
        # 生成结果文件
        self.generate_results(improved_schedule, improved_objectives)
        
        return improved_schedule, improved_objectives
    
    def generate_results(self, schedule, objectives):
        """生成结果文件"""
        # 生成调度矩阵
        schedule_df = pd.DataFrame(schedule)
        
        # 保存调度矩阵
        schedule_df.to_excel('result11.xlsx', index=False)
        
        # 生成序列文件
        sequence = []
        car_info = {}
        for _, row in self.data.iterrows():
            car_info[row['sequence']] = {
                'config': row['config'],
                'color': row['color'],
                'drive': row['drive']
            }
        
        # 提取调度序列
        for col in range(schedule.shape[1]):
            for row in range(schedule.shape[0]):
                if schedule[row, col] > 0:
                    car_id = schedule[row, col]
                    sequence.append({
                        'sequence': car_id,
                        'config': car_info[car_id]['config'],
                        'color': car_info[car_id]['color'],
                        'drive': car_info[car_id]['drive']
                    })
        
        sequence_df = pd.DataFrame(sequence)
        sequence_df.to_excel('result12.xlsx', index=False)
        
        # 保存目标得分
        objectives_df = pd.DataFrame([objectives])
        objectives_df.to_excel('objectives_scores.xlsx', index=False)
        
        print("结果文件已生成:")
        print("  result11.xlsx - 调度矩阵")
        print("  result12.xlsx - 车辆序列")
        print("  objectives_scores.xlsx - 目标得分")

def main():
    """主函数"""
    optimizer = PBSOptimizer()
    schedule, objectives = optimizer.solve()
    
    return schedule, objectives

if __name__ == "__main__":
    main()